home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 26
/
Cream of the Crop 26.iso
/
program
/
qlib205.zip
/
QLIB.ZIP
/
SRC
/
QLIB
/
SPAWN.ASM
< prev
next >
Wrap
Assembly Source File
|
1997-07-08
|
13KB
|
696 lines
;todo : make sure there is no '*' or '?' in the path or filename
; : this is not really necessary cause the 4b00h call will fail anyways
;BUG! overlay simply calls program and then quits if successful
;FIX! : v2.02 : enviroment lookup was fixed
include qlib.inc
include process.inc
include string.inc
include dos.inc
include stdlib.inc
include alloc.inc
include errno.inc
include stdio.inc
;Spawn and all it's variants were hard to implement.
;Everything is supported.
.data?
dopath db ? ;flag - search fn for program
doenv db ? ;flag - made new enviroment
dot db ? ;flag - a . is in fn
bat db ? ;flag - filename is a BAT file
fn dd ? ;filename to exec
fnl dd ? ;length of filename
mode dw ? ;from func (P_WAIT=0 P_NOWAIT=1[error] P_OVERLAY=2)
arglen db ? ;parameters len
args db 128 dup (?) ;parameters (arguments)
ff ffblk <>
path dd ? ;pts to %PATH% in the enviroment
thepath db 128 dup (?) ;a part of %PATH%
totalpath db 128 dup (?) ;path and filename
tfnl dd ? ;total file name length
envirohand dd ? ;handle for enviro memory block (32k)
.data
pbs struct ;parameter block
enviroff dd ?
envirsel dw ?
cto dd offset arglen ;command tail
cts dw ?
fcb1 dd 0
fcb2 dd 0
pbs ends
pb pbs <>
.code
findit proc private,p:dword,at:byte
local len:dword
;looks for program "p+fn"
;if at==\\ then a \\ is not added between 'p' and 'fn'
;at is simply the last char of 'p'
callp strlen,p
mov ebx,eax
add ebx,fnl
mov len,ebx
.if ebx>127
mov eax,ERROR
ret
.endif
mov ebx,offset totalpath
callp strcpy,ebx,p
.if at!='\'
callp strcat,ebx,"\\"
inc len
.endif
callp strcat,ebx,fn
callp findfirst,ebx,0h,offset ff
.if !eax
ret ;found it!
.endif
;try and add .COM and .EXE (order is important to follow DOS implementation)
.if len>(127-5)
mov eax,ERROR
ret ;not enough room to add it
.endif
.if dot
mov eax,ERROR
.endif
tryit: ;there is no . so we can add .COM and then .EXE
mov esi,offset totalpath
add esi,len
mov len,esi ;save for ...
callp strcpy,esi,".COM"
callp findfirst,offset totalpath,0h,offset ff
.if !eax
ret
.endif
mov esi,len ;... here
callp strcpy,esi,".EXE"
callp findfirst,offset totalpath,0h,offset ff
;EAX is returned here
ret
findit endp
add_bat proc private
;adds "/C totalpath " in front of all ARGS (if possible)
;changes totalpath to %COMSPEC%
callp strlen,offset totalpath
mov tfnl,eax
add eax,4
xor ebx,ebx
mov bl,arglen
.if ebx>eax
mov eax,ERROR
ret
.endif
sub esp,128 ;reserve space for temp storage
mov ebx,esp
callp memcpy,ebx,offset args,arglen
callp memcpy,offset args," /C ",4
callp memcpy,offset args+4,offset totalpath,tfnl
mov eax,esp
mov ebx,offset args+4
add ebx,tfnl
callp memcpy,ebx,eax,arglen
callp getenv,"COMSPEC"
.if eax==NULL
mov eax,ERROR
add esp,128
ret
.endif
callp strcpy,offset totalpath,eax
mov eax,tfnl
add eax,4
add arglen,al
xor eax,eax
add esp,128
ret
add_bat endp
_spawn proc private
pushad
.if mode == P_NOWAIT
mov errno,EINVAL
jmp bad
.endif
;misc setup
callp strlen,fn
.if eax>127
mov errno,ENOENT ;path not found
jmp bad
.endif
mov fnl,eax
mov edi,fn
mov ecx,eax
mov al,'.'
repnz scasb
.if zero? ;a . was found
mov dot,1
.else
mov dot,0
.endif
callp memicmp,edi,"BAT",3
.if !eax
mov bat,1
.else
mov bat,0
.endif
.if !doenv
;use parent's enviro for child process
mov eax,_environ
mov pb.enviroff,eax
.endif
mov ax,seldata
mov pb.envirsel,ax
mov pb.cts,ax
;find child
callp findit,"",'\' ;make at='\' so that it will not add a '\'
.if !eax
jmp doit
.endif
mov ecx,fn
.if !dopath
mov errno,ENOENT
jmp bad
.endif
;search for '\' or ':' (if any are found then we cannot cruz thru %path%)
mov edi,fn
mov ecx,fnl
mov al,'\'
repnz scasb
.if zero?
mov errno,ENOENT
jmp bad
.endif
mov edi,fn
mov ecx,fnl
mov al,':'
repnz scasb
.if zero?
mov errno,ENOENT
jmp bad
.endif
callp getenv,"PATH"
.if eax==NULL
mov errno,ENOENT
jmp bad
.endif
mov path,eax
tryagain:
mov esi,path
mov edi,offset thepath
mov cl,1
@@:
lodsb
.if ((al==';') || (al==0))
.if !al
mov cl,0 ;Stop after this attempt
.endif
mov al,0
stosb
mov path,esi ;save new pos
jmp tryit
.endif
mov bl,al
stosb
.if edi>offset thepath+120 ;path too long
@@1:
lodsb
.if al==';'
mov path,esi
jmp tryagain
.endif
.if !al
mov errno,ENOENT
jmp bad
.endif
jmp @@1
.endif
jmp @b
tryit:
push ebx
push ecx
callp findit,offset thepath,bl ;does not preserve regs
pop ecx
pop ebx
.if eax==ERROR
.if !cl
mov errno,ENOENT
jmp bad
.endif
jmp tryagain
.endif
doit:
;SPAWN! (or exec)
.if bat
call add_bat
.if eax==ERROR
mov eax,ENOENT
jmp bad
.endif
.endif
.if mode==P_OVERLAY
;OK, exec is very tricky.
;PSP+ah is the terminate vector. which must be changed to something
;that will load something and then go back to COMMAND.COM (or whatever)
;when we terminate (4ch)
;But what memory do we alloc (if we go thru DOS it will be unalloc as
;soon as we end program). We need enough RAM to have a little code and the
;parameter block. Any ideas?
;for now I will simply evec new program and then quit if successful
mov ax,4b00h ;load & exec program
mov edx,offset totalpath
mov ebx,offset pb
int 21h
.if carry?
mov errno,ax
jmp bad
.endif
callp exit,0 ;exit if successful
.else
mov ax,4b00h ;load & exec program
mov edx,offset totalpath
mov ebx,offset pb
int 21h
.if carry?
mov errno,ax
jmp bad
.endif
mov ah,4dh ;get error code of child
int 21h
xor ebx,ebx
mov bl,al
mov [esp+7*4],ebx ;save as EAX
.endif
mov eax,envirohand
.if eax
callp free,eax
.endif
mov edx,_dta
mov ah,1ah
int 21h ;reset DTA
popad
xor eax,eax
ret
bad:
mov edx,_dta
mov ah,1ah
int 21h ;reset DTA
mov eax,envirohand
.if eax
callp free,eax
.endif
popad
mov eax,ERROR
ret
_spawn endp
setarg proc private,va:dword ;ret:eax=pt to next arg after NULL
local len:dword
pushad
mov ebx,va
; mov ecx,128/4 ;clear ARG area (not needed)
; mov edi,offset args
; xor eax,eax
; rep stosd
mov edx,[ebx]
mov ecx,offset args
mov bptr[ecx],' ' ;must insert a leading space
inc ecx
.while edx
callp strlen,edx
mov len,eax
add eax,ecx
.if eax>(126+offset args) ;need a space after para too
popad
mov eax,ERROR
mov errno,E2BIG
ret
.endif
callp strcpy,ecx,edx
add ecx,len
mov bptr[ecx],' '
inc ecx
add ebx,4
mov edx,[ebx]
.endw
add ebx,4 ;pt to next after NULL (in case the enviro array is after it)
mov bptr[ecx],0
sub ecx,offset args
mov arglen,cl
mov [esp+7*4],ebx ;save as EAX
popad
ret
setarg endp
setenv proc private,e:dword
local len:dword
local max:dword
;setup an enviro block
callp malloc,32*1024 ;MAX size of enviro block
.if eax==NULL
mov errno,ENOMEM
mov eax,ERROR
ret
.endif
mov pb.enviroff,eax
mov envirohand,eax
pushad
mov ebx,e
mov edx,[ebx]
mov ecx,eax
mov max,ecx
add max,32*1024
.while edx
callp strlen,edx
mov len,eax
add eax,ecx
add eax,2 ;FIX! v2.02 : we need room for the zero and double zero
cmp eax,max
ja full
callp strcpy,ecx,edx
add ecx,len
inc ecx ;skip over 0
add ebx,4
mov edx,[ebx]
.endw
full:
mov bptr[ecx],0 ;put last 0 (this is the double 0 thingy)
popad
xor eax,eax
ret
setenv endp
;list of args passed
spawnl proc,m:word,tp:dword,va:vararg ;...,NULL
mov eax,tp
mov fn,eax
mov ax,m
mov mode,ax
lea eax,va
callp setarg,eax
.if eax==ERROR
ret
.endif
mov doenv,0 ;use parent's enviroment
mov dopath,0
mov envirohand,0
call _spawn
ret
spawnl endp
spawnle proc,m:word,tp:dword,va:vararg ;...,NULL,char *envp[]
mov eax,tp
mov fn,eax
mov ax,m
mov mode,ax
lea eax,va
callp setarg,eax
.if eax==ERROR
ret
.endif
mov eax,[eax] ;get env
callp setenv,eax
.if eax==ERROR
ret
.endif
mov doenv,1 ;use new enviroment
mov dopath,0
call _spawn
ret
spawnle endp
spawnlp proc,m:word,tp:dword,va:vararg ;...,NULL
mov eax,tp
mov fn,eax
mov ax,m
mov mode,ax
lea eax,va
callp setarg,eax
.if eax==ERROR
ret
.endif
mov doenv,0 ;use parent's enviroment
mov dopath,1
mov envirohand,0
call _spawn
ret
spawnlp endp
spawnlpe proc,m:word,tp:dword,va:vararg ;...,NULL,char *envp[]
mov eax,tp
mov fn,eax
mov ax,m
mov mode,ax
lea eax,va
callp setarg,eax
.if eax==ERROR
ret
.endif
mov eax,[eax] ;get env
callp setenv,eax
.if eax==ERROR
ret
.endif
mov doenv,1 ;new enviroment
mov dopath,1
call _spawn
ret
spawnlpe endp
; V variants follow
spawnv proc,m:word,tp:dword,va:dword
mov eax,tp
mov fn,eax
mov ax,m
mov mode,ax
callp setarg,va
.if eax==ERROR
ret
.endif
mov doenv,0 ;use parent's enviroment
mov dopath,0
mov envirohand,0
call _spawn
ret
spawnv endp
spawnve proc,m:word,tp:dword,va:dword,e:dword
mov eax,tp
mov fn,eax
mov ax,m
mov mode,ax
callp setarg,va
.if eax==ERROR
ret
.endif
callp setenv,e
.if eax==ERROR
ret
.endif
mov doenv,1 ;use parent's enviroment
mov dopath,0
call _spawn
ret
spawnve endp
spawnvp proc,m:word,tp:dword,va:dword
mov eax,tp
mov fn,eax
mov ax,m
mov mode,ax
callp setarg,va
.if eax==ERROR
ret
.endif
mov doenv,0 ;use parent's enviroment
mov dopath,1
mov envirohand,0
call _spawn
ret
spawnvp endp
spawnvpe proc,m:word,tp:dword,va:dword,e:dword
mov eax,tp
mov fn,eax
mov ax,m
mov mode,ax
callp setarg,va
.if eax==ERROR
ret
.endif
callp setenv,e
.if eax==ERROR
ret
.endif
mov doenv,1 ;use parent's enviroment
mov dopath,1
call _spawn
ret
spawnvpe endp
;list of args passed
execl proc,tp:dword,va:vararg ;...,NULL
mov eax,tp
mov fn,eax
lea eax,va
callp setarg,eax
.if eax==ERROR
ret
.endif
mov doenv,0 ;use parent's enviroment
mov dopath,0
mov mode,P_OVERLAY
mov envirohand,0
call _spawn
ret
execl endp
execle proc,tp:dword,va:vararg ;...,NULL,char *envp[]
mov eax,tp
mov fn,eax
lea eax,va
callp setarg,eax
.if eax==ERROR
ret
.endif
mov eax,[eax] ;get env
callp setenv,eax
.if eax==ERROR
ret
.endif
mov doenv,1 ;use new enviroment
mov dopath,0
mov mode,P_OVERLAY
call _spawn
ret
execle endp
execlp proc,tp:dword,va:vararg ;...,NULL
mov eax,tp
mov fn,eax
lea eax,va
callp setarg,eax
.if eax==ERROR
ret
.endif
mov doenv,0 ;use parent's enviroment
mov dopath,1
mov mode,P_OVERLAY
mov envirohand,0
call _spawn
ret
execlp endp
execlpe proc,tp:dword,va:vararg ;...,NULL,char *envp[]
mov eax,tp
mov fn,eax
lea eax,va
callp setarg,eax
.if eax==ERROR
ret
.endif
mov eax,[eax] ;get env
callp setenv,eax
.if eax==ERROR
ret
.endif
mov doenv,1 ;new enviroment
mov dopath,1
mov mode,P_OVERLAY
call _spawn
ret
execlpe endp
; V variants follow
execv proc,tp:dword,va:dword
mov eax,tp
mov fn,eax
callp setarg,va
.if eax==ERROR
ret
.endif
mov doenv,0 ;use parent's enviroment
mov dopath,0
mov mode,P_OVERLAY
mov envirohand,0
call _spawn
ret
execv endp
execve proc,tp:dword,va:dword,e:dword
mov eax,tp
mov fn,eax
callp setarg,va
.if eax==ERROR
ret
.endif
callp setenv,e
.if eax==ERROR
ret
.endif
mov doenv,1 ;use parent's enviroment
mov dopath,0
mov mode,P_OVERLAY
call _spawn
ret
execve endp
execvp proc,tp:dword,va:dword
mov eax,tp
mov fn,eax
callp setarg,va
.if eax==ERROR
ret
.endif
mov doenv,0 ;use parent's enviroment
mov dopath,1
mov mode,P_OVERLAY
mov envirohand,0
call _spawn
ret
execvp endp
execvpe proc,tp:dword,va:dword,e:dword
mov eax,tp
mov fn,eax
callp setarg,va
.if eax==ERROR
ret
.endif
callp setenv,e
.if eax==ERROR
ret
.endif
mov doenv,1 ;use parent's enviroment
mov dopath,1
mov mode,P_OVERLAY
call _spawn
ret
execvpe endp
end